﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;

namespace AirLib
{
    /// <summary>
    /// This is meant to listen for the return call from the Apple TV "reverse" protocol, but does not appear to function properly
    /// </summary>
    public class EventListener
    {

        #region Fields
        private HttpListener _httpListener = new HttpListener();
        private string _localPath;
        #endregion Fields

        public EventListener(int port, string localPath)
        {
            _localPath = localPath;

            _httpListener.Prefixes.Add("http://*:" + port + "/");
            _httpListener.Start();
            IAsyncResult result = _httpListener.BeginGetContext(new AsyncCallback(ListenerCallback), _httpListener);
            _httpListener.IgnoreWriteExceptions = true;     
                  
        }




        public void ListenerCallback(IAsyncResult result)
        {
            HttpListener listener = (HttpListener)result.AsyncState;
            

            // Call EndGetContext to complete the asynchronous operation.
            HttpListenerContext context = listener.EndGetContext(result);

            _httpListener.BeginGetContext(new AsyncCallback(ListenerCallback), _httpListener);
            
            //Obtain the request object.
            HttpListenerRequest request = context.Request;

            FileInfo fileInfo = new FileInfo(_localPath + request.RawUrl.Replace(@"/", @"\"));           
            

            //Figure out the range of bytes requested by the AppleTV
            int startRange;
            int endRange;
            if (request.Headers["Range"] != null)
            {
                string requestedRange = request.Headers["Range"].Replace("bytes=", string.Empty);
                startRange = int.Parse(requestedRange.Split('-').First());
                endRange = int.Parse(requestedRange.Split('-').Last());
            }
            else
            {
                startRange = 0;
                endRange = (int)fileInfo.Length;
            }

            
            // Obtain the response object.
            HttpListenerResponse response = context.Response;

            // Construct a response.
            response.StatusCode = (int)HttpStatusCode.PartialContent;
            response.KeepAlive = true;            
            response.Headers[HttpResponseHeader.Server] = "AirLib/1.0";
            response.Headers[HttpResponseHeader.ContentRange] = "bytes " + startRange + "-" + endRange + "/" + fileInfo.Length;
            response.Headers[HttpResponseHeader.ContentType] = GuessContentType(fileInfo.Extension);
            response.Headers[HttpResponseHeader.CacheControl] = "no-cache";
            response.Headers[HttpResponseHeader.Connection] = "Close";               
            
            byte[] buffer = new byte[endRange - startRange + 1];
            response.ContentLength64 = buffer.Length;


            using (FileStream fileStream = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                fileStream.Seek(startRange,0);
                fileStream.Read(buffer, 0, buffer.Length);                
                fileStream.Close();
            }

            System.IO.Stream output = response.OutputStream;
            try
            {
                //Note: AppleTV seems to like to terminate stream and restart using another connnection
                //Error here does not indicate that streaming process has failed.
                output.Write(buffer, 0, buffer.Length);
                output.Close();
            }
            catch (Exception)
            {
                response.Abort();
            }
            finally
            {
                response.Close();
            }
            
        }

        static string GuessContentType(string ext)
        {
            switch (ext)
            {
                case ".mov":
                    return "video/quicktime";
                case ".m4v":
                    return "video/x-m4v";
                case ".avi":
                    return "video/x-msvideo";
                case ".mpg":
                    return "video/mpeg";
                case ".dvr-ms":
                    return "video/x-msvideo";
                case ".mp4":
                    return "video/mp4";
                case ".wmv":
                    return "video/x-ms-wmv";
                default:
                    return "application/octet-stream";
            }
        }
    }
}
